Fix identity query hanging indefinitely outside a Tauri runtime - #3189
Open
jefflitt1 wants to merge 2 commits into
Open
Fix identity query hanging indefinitely outside a Tauri runtime#3189jefflitt1 wants to merge 2 commits into
jefflitt1 wants to merge 2 commits into
Conversation
When the desktop chat UI is served as a plain web page (no window.__TAURI_INTERNALS__), get_identity() has no way to succeed, so useIdentityQuery's queryFn always rejects. With the default retry config, the single configured retry can call the query-core retryer's pause() path if the window isn't focused at that exact moment (canContinue() requires focusManager.isFocused() regardless of networkMode) — leaving the query stuck on fetchStatus "paused" forever instead of ever settling to "error". Any consumer gating UI on this query's settled status (success/error) then hangs indefinitely, since neither state is ever reached. - useIdentityQuery: retry: false — a missing native identity backend can't be fixed by retrying, so there's no reason to ever enter the retry/pause branch. - tauriIdentity.ts: guard get_identity/get_nsec/import_identity/ persist_current_identity/sign_out with isTauri(), matching the guard convention already used elsewhere in this codebase (e.g. audioWorklet.ts), so a missing runtime produces a clean, identifiable Error instead of a raw "Cannot read properties of undefined (reading 'invoke')" TypeError surfaced from deep inside invoke().
4 tasks
Covers the actual failure mode this PR fixes: get_identity and its siblings must never reach invokeTauri when there is no Tauri runtime. Without this guard the query hung on fetchStatus "paused" instead of settling to "error" — these tests assert the guard short-circuits before any native call is attempted, and that it doesn't when Tauri is available. The "Tauri available" happy-path case lives in its own file (tauriIdentity.available.test.mjs) rather than alongside the "unavailable" cases: node's per-process ESM module cache means mixing an isTauri: () => true mock with an isTauri: () => false mock in the same test file causes a later import of tauriIdentity.ts to return the first test's cached module instance instead of re-evaluating against the new mock. node --test already runs each matched file in its own process, which sidesteps that. Requires --experimental-test-module-mocks (added to the test script) for node:test's t.mock.module — available in the project's pinned Node version (22.22.3) but not previously enabled.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
window.__TAURI_INTERNALS__), whereget_identity()can never succeed.useIdentityQuery'squeryFnalways rejects in that environment, and with the default retry config the single configured retry can hit query-core'spause()path if the window isn't focused at that exact moment —canContinue()requiresfocusManager.isFocused()regardless ofnetworkMode. The query then gets stuck onfetchStatus: "paused"forever instead of ever settling to"error", so anything gating UI on the query's settled status hangs indefinitely.retry: falseonuseIdentityQuery— a missing native identity backend can't be fixed by retrying, so there's no reason to ever enter that retry/pause branch.get_identity/get_nsec/import_identity/persist_current_identity/sign_outwithisTauri(), matching the guard convention already used elsewhere in this codebase (e.g.audioWorklet.ts), so a missing runtime produces a clean, identifiableErrorinstead of a rawTypeErrorsurfaced from deep insideinvoke().Test plan
pnpm build(tsc + vite build) passespnpm test— 3662/3662 passingpnpm exec biome checkon both touched files — clean"error"immediately instead of hanging onpending/pausedRelated
Checked open PRs/issues for duplicates before submitting — no duplicate found. #3027 is open in an adjacent but different subsystem (relay-side SPA routing config, vs. this PR's desktop-client Tauri guards) for a similarly-motivated self-hosted deployment; not overlapping, noted for context.